home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / PC_LIBS / C045.ZIP / CBEAUT.ARC / CB.C next >
C/C++ Source or Header  |  1988-09-18  |  41KB  |  1,114 lines

  1. /*===========================================================================
  2. cb.c  -  C program indenter
  3.  
  4. Revision History:
  5.   08/08/87  Robert B. Sledge (Compuserve 76515,2620):
  6.         Obtained cb.c source from C User's Group.
  7.         Added extensive comments (there were none).
  8.         Changed operation to rename original file to .BAK and
  9.         write output to file of original name.
  10.         Added support for variable indent_spaces.
  11.         Added switches -s, -b, and -l to command line.
  12.         Corrected a number of processing bugs.
  13.         Compiled with Microsoft C 4.0 compiler.
  14.         Added switches to compile under VAX/VMS.
  15.  
  16.   10/30/83  John W. Kindschi Jr.: Modified for Lattice C Ver 1.01
  17.  
  18.   ??/??/??  William C. Colley, III: Swiped from CPIG'S UNIX system and
  19.         modified to run under BDS C.
  20.  
  21. Usage: cb [-blis] inputfile [inputfile...]
  22.  
  23. Switches:
  24.  
  25.      -b    Braces indent at level of outside code.
  26.        (Default = indent at level of inside code.)
  27.      -l    Indentation starts at level 1.
  28.        (Default = indentation starts at level 0.)
  29.      -inn  Set number of spaces per indentation level to nn.
  30.        (Default = indentation set to 3 spaces per level.)
  31.      -s    Output written to standard output.
  32.        (Default = output to file, rename old .BAK.)
  33.  
  34.  Where inputfile is the file to be pretty printed (the filename may
  35.  contain wildcard characters).  Under MS-DOS the original file is renamed to
  36.  .BAK unless the -s switch is used.  Under VAX/VMS a new version of the file
  37.  is created.
  38. ===========================================================================*/
  39.  
  40.  
  41. #include <stdio.h>
  42. #ifndef vms
  43. #include <errno.h>               /* for the MSC rename() function */
  44. #endif
  45.  
  46. #define TEMPNAME  "cbtemp.czz"   /* temp output file name */
  47. #define SORTOF    2
  48. #define YES       1
  49. #define NO        0
  50.  
  51. #define BRACES_OUTSIDE  0        /* braces at outside block level */
  52. #define BRACES_INSIDE   1        /* braces at inside  block level */
  53.  
  54. #define START0LEVEL 0            /* indenting starts at level 0 */
  55. #define START1LEVEL 1            /* indenting starts at level 1 */
  56.  
  57. #define  SUCCESS  0              /* return codes for renambak() */
  58. #define  FAILURE1 -1
  59. #define  FAILURE2 -2
  60.  
  61. #define  MAXBRACE  20            /* max nested brace level allowed */
  62. #define  MAXIF     10            /* max nested 'if' level allowed    */
  63. #define  MAXLEVEL  10            /* max number of braced blocks preceeded by
  64.                   *   non-braced block statements */
  65.  
  66. int swflg = NO;                  /* processing 'switch' flag */
  67. int sswflg[MAXBRACE];            /* saved 'swflg's */
  68.  
  69. int aflg[MAXLEVEL];              /* YES/NO flag (has to do with braces???) */
  70. int saflg[MAXBRACE][MAXIF];      /* saved aflg[] */
  71. int nblk[MAXLEVEL];              /* non-braced blocks at current 'level' */
  72. int snblk[MAXBRACE][MAXIF];      /* saved nblks[] */
  73. int brclev = 0;                  /* brace {} level: increments on '{'
  74.                   *  and decrements on '}'            */
  75. int sbrclev[MAXLEVEL];           /* saved 'brclev's */
  76. int iflev = 0;                   /* 'if' level */
  77. int siflev[MAXBRACE];            /* saved 'iflev's */
  78. int ifflg = -1;                  /* processing 'if' flag */
  79. int sifflg[MAXBRACE];            /* saved 'ifflg's */
  80. int tabs = 0;                    /* current level of indentation */
  81. int stabs[MAXBRACE][MAXIF];      /* saved 'tabs' */
  82. int level = 0;                   /* brace level after non-braced block stmt */
  83. int addflg = NO;                 /* add-extra-indent flag */
  84. int elseflg = NO;                /* processing 'else' flag */
  85. int qflg = NO;                   /* question mark flag */
  86. int solflg = YES;                /* start-of-line flag */
  87. int stdoutflg = NO;              /* flag to use stdout for output */
  88. int tabsflg = START0LEVEL;       /* indenting starts at level 0 */
  89. int paren = 0;                   /* 'parenthesis' level */
  90. int peek = -1;                   /* peekahead character */
  91. int j = 0;                       /* char index for output buffer */
  92. int nindent = 3;                 /* number of spaces per indent level */
  93. int braces = BRACES_INSIDE;      /* braces indent at inside block level */
  94. FILE *inpfile, *outfile;         /* input and output file pointers */
  95.  
  96. static char string[200];         /* output string buffer */
  97.  
  98. char *wif[2]    = { "if",     NULL };
  99. char *welse[2]  = { "else",   NULL };
  100. char *wfor[2]   = { "for",    NULL };
  101. char *wcase[3]  = { "case", "default", NULL };
  102. char *wswitch[2]= { "switch", NULL };
  103. char lchar;     /* last non-whitespace && non-comma char written to output */
  104. char pchar;     /* previous non-whitespace char from input stream          */
  105. int  lastchar;                   /* last character received */
  106. int  c;                          /* character buffer */
  107. char cc;                         /* character buffer */
  108.  
  109.  
  110. main( argc, argv)
  111. int argc;
  112. char **argv;
  113. {
  114. void  cb();                      /* main processing function */
  115. char *findfile();                /* vms wildcard processing routine */
  116. int   n;                         /* loop index variable */
  117. char  *arg;                      /* ptr to command line character */
  118. char  *ptr;                      /* ptr to filename string */
  119.  
  120. /* show the correct usage of this utility */
  121. if (argc <= 1)
  122.    {
  123.    fprintf(stderr, "V2.1 Usage: cb [-blis] inputfile [inputfile...]\n");
  124.    fprintf(stderr, "  Switches:\n\n");
  125.    fprintf(stderr, "  -b    Braces indent at level of outside code.\n");
  126.    fprintf(stderr, "        (Default = indent at level of inside code.)\n");
  127.    fprintf(stderr, "  -l    Indentation starts at level 1.\n");
  128.    fprintf(stderr, "        (Default = indentation starts at level 0.)\n");
  129.    fprintf(stderr, "  -inn  Set number of spaces per indentation level to nn.\n");
  130.    fprintf(stderr, "        (Default = indentation set to 3 spaces per level.)\n");
  131.    fprintf(stderr, "  -s    Output written to standard output.\n");
  132. #ifdef vms
  133.    fprintf(stderr, "        (Default = Create a new version of the file.)\n");
  134. #else
  135.    fprintf(stderr, "        (Default = output to file, rename old .BAK.)\n");
  136. #endif
  137.    return;
  138.    }
  139.  
  140. /* process command line tokens */
  141. while( --argc > 0)
  142.    {
  143.    /* process a command line switch */
  144.    arg = *++argv;
  145.    if ( *arg == '-')
  146.    {
  147.       /* handle multiple switches behind a single '-' */
  148.       while( *++arg != '\0')
  149.      switch (*arg)
  150.         {
  151.         default:
  152.            fprintf(stderr, "Unknown Switch (-%c)...  Ignored!!\n", *arg);
  153.            break;
  154.  
  155.         case 'b':
  156.         case 'B':
  157.            braces = BRACES_OUTSIDE;        /* braces at outside code level */
  158.            break;
  159.  
  160.         case 'i':
  161.         case 'I':
  162.            if ((n=atoi(++arg)) > 0)
  163.           nindent = n;                  /* set spaces per indent */
  164.            /* skip over the digits in the number */
  165.            while (*(arg+1) >= '0' && *(arg+1) <= '9')
  166.           arg++;
  167.            break;
  168.  
  169.         case 'l':
  170.         case 'L':
  171.            tabsflg = START1LEVEL;           /* indentation starts at level 1 */
  172.            break;
  173.  
  174.         case 's':
  175.         case 'S':
  176.            stdoutflg = YES;                 /* output goes to standard out */
  177.            break;
  178.         } /* end switch() */
  179.       }
  180.    /* not a command line switch: process as a filename */
  181.    else
  182.       {
  183. #ifdef vms
  184.       /* findfile() returns ptr to matching (possibly wildcard) file specs.
  185.        *   this is where we handle wildcards for vms */
  186.       while ( (ptr=findfile(arg)) != NULL)
  187.          cb( ptr);               /* process the filename ptd to by 'ptr' */
  188. #else
  189.       cb( arg);                  /* process the filename ptd to by 'arg' */
  190. #endif
  191.       }
  192.  
  193.    } /* end while() to process command line tokens */
  194.  
  195. } /*----------------------------- main() --------------------------------*/
  196.  
  197.  
  198. /*-----------------------------------------------------------------------*
  199.  * cb()  -  beautify the specified file
  200.  *
  201.  * Synopsis:
  202.  *   cb( filename)
  203.  *   char *filename;                   ptr to name of file to process
  204.  *
  205.  * Returns: void
  206.  *-----------------------------------------------------------------------*/
  207.  
  208. void cb( filename)
  209. char  *filename;              /* ptr to name of file to process */
  210. {
  211. int ct;
  212. int i,n;                      /* temp variables */
  213.  
  214. /* open the input file */
  215. if ( (inpfile = fopen(filename,"r")) == NULL)
  216.    {
  217.    fprintf(stderr, "\nFile (%s) not found.\n\n", filename);
  218.    return;
  219.    }
  220.  
  221. /* open the output stream */
  222. if (stdoutflg == NO)
  223.    {
  224. #ifdef vms
  225.    /* remove explicit version number so file defaults to next higher version */
  226.    for( n = strlen(filename); n >= 0; n--)
  227.       if (filename[n] == ';')
  228.          filename[n] = '\0';
  229.    if ((outfile = fopen(filename,"w")) == NULL)
  230.       {
  231.       fprintf( stderr, "Couldn't create output file (%s).\n", filename);
  232.       return;
  233.       }
  234. #else /* non-vms */
  235.    if ((outfile = fopen(TEMPNAME,"w")) == NULL)
  236.       {
  237.       fprintf( stderr, "Couldn't create output file (%s).\n", filename);
  238.       return;
  239.       }
  240. #endif
  241.    }
  242. /* open the output stream to stdout */
  243. else
  244.    outfile = stdout;
  245.  
  246. /* initialize parameters */
  247. cbinit();
  248.  
  249. /* process the characters from the input file and send to output stream */
  250. while ( (c=getchr()) != EOF)
  251.    {
  252.    switch(c)                        /* switch on input character */
  253.       {
  254.       /* not a special character: just pack it into output string */
  255.       default:
  256.      string[j++] = c;
  257.      if (c != ',')
  258.         lchar = c;              /* remember last character */
  259.      break;
  260.  
  261.       /* handle a whitespace character */
  262.       case ' ':
  263.       case '\t':
  264.      if (lookup(welse) == YES)  /* processing an 'else' */
  265.         {
  266.         elseflg = SORTOF;       /* remember the 'else' statement */
  267.         gotelse();              /* adjust for the 'else' */
  268.         /* not start-of-line or characters in output buffer */
  269.         if( solflg == NO || j > 0)
  270.            string[j++] = c;     /* copy whitespace to output buf */
  271.         putb();                 /* write output buffer */
  272.         solflg = NO;            /* not start-of-line */
  273.         break;                  /* loop back around */
  274.         }
  275.      /* not start-of-line or chars in buffer */
  276.      if (solflg == NO  ||  j > 0)
  277.         string[j++] = c;        /* copy whitespace to output buf */
  278.      break;                     /* loop back around */
  279.  
  280.       /* handle a newline character */
  281.       case '\n':
  282.      /* Check for processing an 'else' statement.
  283.       * Elseflg may have been set previously by the ' ' or '\t' special
  284.       * character case statement, in which case gotelse() has already
  285.       * been called and we don't want to call it again here.  Note that
  286.       * we won't detect the else here in that case since putb() has
  287.       * been called and flushed the 'else' to the output stream.  In order
  288.       * to help us here we set elseflg=SORTOF back there so we can go ahead
  289.       * and appropriately handle the 'else' here.
  290.       */
  291.      if (elseflg != SORTOF  &&  (elseflg=lookup(welse)) == YES)
  292.         gotelse();              /* adjust for this 'else' stmt */
  293.      putb();                    /* write output buffer */
  294.      fprintf( outfile, "\n");   /* write newline to output stream */
  295.      solflg = YES;              /* start-of-line is true */
  296.      /* we are processing an 'else' */
  297.      if (elseflg == YES  ||  elseflg == SORTOF)
  298.         {
  299.         nblk[level]++;          /* increment non-braced block count */
  300.         tabs++;                 /* stuff after 'else' is indented   */
  301.         elseflg = NO;           /* reset the flag                   */
  302.         }
  303.      /* somewhere inside parenthesis: add an extra temp indent */
  304.      else if( paren > 0)
  305.         addflg = YES;
  306.      break;                     /* loop back around */
  307.  
  308.       /* handle a left brace */
  309.       case '{':
  310.      if (lookup(welse) == YES)  /* processing an 'else' */
  311.         gotelse();
  312.      siflev[brclev] = iflev;    /* save 'if' level */
  313.      sifflg[brclev] = ifflg;    /* save 'if' flag  */
  314.      iflev = 0;                 /* current 0 at new brace level */
  315.      ifflg = NO;                /* no 'if's yet at new brace level */
  316.      sswflg[brclev] = swflg;    /* save 'switch' flag  */
  317.      if (++brclev > MAXBRACE)   /* increment brace level */
  318.             {
  319.             fprintf(stderr,"Too many nested braces in (%s), aborting!!\n",
  320.                filename);
  321.             goto END;
  322.             }
  323.      /* start-of-line and non-braced block statements above us */
  324.      if (solflg == YES && nblk[level] > 0)
  325.         {
  326.         nblk[level]--;          /* decrement since we now have a brace */
  327.         tabs--;                 /*  and it will indent things for us   */
  328.         }
  329.      string[j++] = c;           /* store '{' in output buffer */
  330.      /* braces at inside block level (never for switch stmt) */
  331.      if (swflg == NO  &&  braces == BRACES_INSIDE)
  332.         tabs++;                 /* indent right one level */
  333.      putb();                    /* write buffer to output stream */
  334.      getnl();                   /* get remaining whitespace & comments */
  335.      putb();                    /* write buffer to output stream */
  336.      fprintf( outfile, "\n");   /* write newline to output stream */
  337.      solflg = YES;              /* start-of-line is true */
  338.      /* braces at outside block level (always for switch stmt) */
  339.      if (swflg == YES  ||  braces == BRACES_OUTSIDE)
  340.         tabs++;                 /* indent right one level */
  341.      swflg = NO;                /* no 'switch's yet at this level */
  342.      /* some non-braced block statements above us at this 'level' */
  343.      if (nblk[level] > 0)
  344.         {
  345.         aflg[level] = YES;            /* set flag true                    */
  346.         /* start new brace level following some non-braced block stmts */
  347.         if (++level > MAXLEVEL)
  348.                {
  349.                fprintf(stderr,"Too many nested braces in (%s), aborting!!\n",
  350.                   filename);
  351.                goto END;
  352.                }
  353.         sbrclev[level] = brclev;      /* save the brace level             */
  354.         }
  355.      break;                           /* loop back around */
  356.  
  357.       /* handle a right brace */
  358.       case '}':
  359.      brclev--;                        /* decrement the brace level */
  360.      if ((iflev = siflev[brclev]-1) < 0)
  361.         iflev = 0;
  362.      ifflg = sifflg[brclev];          /* restore 'if' flag at level */
  363.      swflg = sswflg[brclev];          /* restore 'switch' flag      */
  364.      putb();                          /* write output buffer */
  365.      /* braces at outside block level (always for switch stmt) */
  366.      if (swflg == YES  ||  braces == BRACES_OUTSIDE)
  367.         tabs--;                       /* indent left one level */
  368.      ptabs();                         /* output leading indentation */
  369.      /* braces at inside block level (never for switch stmt) */
  370.      if (swflg == NO  &&  braces == BRACES_INSIDE)
  371.         tabs--;                       /* indent left one level */
  372.      swflg = sswflg[brclev] = NO;     /* no 'switch' stmt at this point */
  373.      /* peek at next character, it is a semicolon ';' */
  374.      if ((peek = getchr()) == ';')
  375.         {
  376.         fprintf(outfile, "%c;", c);   /* output the "};" to buffer */
  377.         peek = -1;                    /* forget the ';' */
  378.         }
  379.      /* next character is not a semicolon ';' */
  380.      else
  381.         fprintf( outfile, "%c", c);   /* output the '}' to buffer */
  382.      getnl();                   /* get remaining whitespace & comments */
  383.      putb();                    /* write output buffer */
  384.      fprintf( outfile, "\n");   /* write newline to output stream */
  385.      solflg = YES;              /* start-of-line is true */
  386.      /* conditions are right to decrement non-blocked brace level */
  387.      if (brclev < sbrclev[level])
  388.         if (level > 0)
  389.            level--;             /* decrement non-blocked brace level */
  390.      /* leaving a braced block preceeded by non-braced block stmts   */
  391.      /*  adjust things accordingly                                   */
  392.      if (aflg[level] > 0)
  393.         {
  394.         tabs -= nblk[level];    /* indent left appropriate number    */
  395.         nblk[level] = 0;        /* no non-braced blocks at 'level' now */
  396.         aflg[level] = NO;       /* reset the aflg[] flag */
  397.         }
  398.      break;                     /* loop back around */
  399.  
  400.       /* handle a single quote or double quote */
  401.       case '"':
  402.       case '\'':
  403.      string[j++] = c;              /* copy quote to output buffer */
  404.      /* copy characters within quotes to output buffer */
  405.      while ( (cc=getchr()) != c)
  406.         {
  407.         string[j++] = cc;          /* copy char to output buffer */
  408.         if( cc == '\\')            /* copy an escaped character */
  409.            string[j++] = getchr(); /* straight into output buffer */
  410.         if (cc == '\n')         /* we have a newline */
  411.            {
  412.            putb();              /* write output buffer */
  413.            solflg = YES;        /* start-of-line is true */
  414.            }
  415.         }
  416.      string[j++] = cc;          /* copy last char to output buffer */
  417.      /* get remaining whitespace & comments: we hit a newline */
  418.      if (getnl() == YES)
  419.         {
  420.         lchar = cc;             /* remember last character */
  421.         peek = '\n';            /* remember the newline */
  422.         }
  423.      break;                     /* loop back around */
  424.  
  425.       /* handle a semicolon */
  426.       case ';':
  427.      string[j++] = c;
  428.      putb();
  429.      /* leaving one or more non-braced block statements */
  430.      if (nblk[level] > 0 && aflg[level] == NO)
  431.         {
  432.         tabs -= nblk[level];    /* indent left an appropriate amount */
  433.         nblk[level] = 0;        /* no non-braced blocks at 'level' now */
  434.         }
  435.      getnl();                   /* get remaining whitespace & comments */
  436.      putb();                    /* write the output buffer */
  437.      fprintf( outfile, "\n");   /* write a newline to output stream */
  438.      solflg = YES;              /* start-of-line is true */
  439.      /* we are in one or more nested 'if' statements */
  440.      if (iflev > 0)
  441.         /* we are currently processing an 'if' statement */
  442.         if (ifflg == YES)
  443.            {
  444.            iflev--;             /* decrement 'if' level */
  445.            ifflg = NO;          /* and reset the 'if' flag */
  446.            }
  447.         /* not currently processing an 'if' statement */
  448.         else
  449.            iflev = 0;           /* not in nested 'if' stmts any more */
  450.      break;
  451.  
  452.       /* handle an escaped character; copy both to output string */
  453.       case '\\':
  454.      string[j++] = c;           /* copy the '\' */
  455.      string[j++] = getchr();    /* copy the character */
  456.      break;
  457.  
  458.       /* handle a question mark; it may be a conditional operator (?:) */
  459.       case '?':
  460.      qflg = YES;                /* remember the '?' */
  461.      string[j++] = c;           /* copy to output string */
  462.      break;
  463.  
  464.       /* handle a colon */
  465.       case ':':
  466.      string[j++] = c;           /* copy to output string */
  467.      /* we are processing a conditional operator (?:) */
  468.      if (qflg == YES)
  469.         {                       /* no further processing needed */
  470.         qflg = NO;              /* just cancel the flag */
  471.         break;                  /* and loop back around */
  472.         }
  473.      /* processing 'case' or 'default' */
  474.      if (lookup(wcase) == YES)
  475.         {
  476.         tabs--;                 /* indent left */
  477.         putb();                 /* write the "case:" or "default:" */
  478.         tabs++;                 /* indent right */
  479.         }
  480.      /* not conditional operator (?:) or case: or default: */
  481.      else
  482.         {
  483.         solflg = NO;            /* start-of-line is false */
  484.         putb();                 /* write the output buffer */
  485.         }
  486.      /* if next character is a semicolon */
  487.      if ((peek = getchr()) == ';')
  488.         {
  489.         fprintf( outfile, ";"); /* then output the ';' */
  490.         peek = -1;              /* don't remember the peek */
  491.         }
  492.      getnl();                   /* get remaining whitespace and comments */
  493.      putb();                    /* write the output buffer */
  494.      fprintf( outfile, "\n");   /* write a newline to output stream */
  495.      solflg = YES;              /* start-of-line is true */
  496.      break;                     /* loop back around */
  497.  
  498.       /* handle a slash */
  499.       case '/':
  500.      string[j++] = c;           /* copy to output buffer */
  501.      if ( (peek=getchr()) != '*')   /* next char is not a '*' */
  502.         break;                  /* loop back around */
  503.      string[j++] = peek;        /* copy '*' to output buffer */
  504.      peek = -1;                 /* forget the peek */
  505.      comment();                 /* handle rest of the comment */
  506.      break;                     /* loop back around */
  507.  
  508.       /* handle a left parenthesis */
  509.       case '(':
  510.      string[j++] = c;           /* copy '(' to the output buffer */
  511.      paren++;                   /* increment paren level */
  512.      /* processing 'for' statement */
  513.      if (lookup(wfor) == YES)
  514.         {
  515.         /* gobble till we process a semicolon */
  516.         while( (c=cgets()) != ';')
  517.            ;
  518.         ct = 0;                 /* no nesting yet */
  519. cont:
  520.         /* gobble till we process a right paren */
  521.         while ( (c=cgets()) != ')')
  522.            {
  523.            if (c == '(')        /* we hit a left paren */
  524.           ct++;             /* increment nesting level */
  525.            }
  526.         /* we are still nested: keep gobbling */
  527.         if (ct != 0)
  528.            {
  529.            ct--;                /* decrease nesting level     */
  530.            goto cont;           /* and continue gobbling till */
  531.            }                    /* we find the right paren    */
  532.  
  533.         paren--;                /* decrement paren level */
  534.         putb();                 /* put the output line out */
  535.  
  536.         /* output whitespace and comments: handle multi-line 'for' */
  537.         if (getnl() == YES)     /* we got to a newline */
  538.            {
  539.            peek = '\n';         /* remember the newlne */
  540.            nblk[level]++;       /* increment non-braced block level */
  541.            tabs++;              /* indent right */
  542.            aflg[level] = NO;    /* reset the flag */
  543.            }
  544.         break;                  /* loop back around */
  545.         } /* end 'for' processing */
  546.  
  547.      /* processing an 'if' statement */
  548.      if (lookup(wif) == YES)
  549.         {
  550.         putb();                 /* write output buffer */
  551.         stabs[brclev][iflev] = tabs;           /* save current state */
  552.         snblk[brclev][iflev] = nblk[level];
  553.         saflg[brclev][iflev] = aflg[level];
  554.             if (++iflev > MAXIF)    /* increment the 'if' level */
  555.                {
  556.                fprintf(stderr,"Too many nested 'if's in (%s), aborting!!\n",
  557.           filename);
  558.                goto END;
  559.                }
  560.         ifflg = YES;            /* show that we are doing an 'if' stmt */
  561.         } /* end 'if' processing */
  562.  
  563.      /* processing a 'switch' statement: set the flag */
  564.      if (lookup(wswitch) == YES)
  565.         swflg = YES;            /* show that we're in 'switch' stmt */
  566.      break;                     /* loop back around */
  567.  
  568.       /* handle a right parenthesis */
  569.       case ')':
  570.      paren--;                   /* decrement paren level */
  571.      string[j++] = c;           /* copy ')' to output buffer */
  572.      putb();                    /* write output buffer */
  573.      /* get remaining whitespace and comments: we hit a newline */
  574.      if (getnl() == YES)
  575.         {
  576.         peek = '\n';            /* remember the newline we hit */
  577.         if (paren != 0)         /* we are inside parens */
  578.            addflg = YES;        /* add-extra-indent is true */
  579.         /* This is the where block statements that are terminated
  580.          * by a right parenthesis receive their indentation. */
  581.         else if (tabs > 0)      /* we are indented */
  582.            {
  583.            nblk[level]++;       /* increment non-braced block level */
  584.            tabs++;              /* indent right one level */
  585.            aflg[level] = NO;    /* reset the flag */
  586.            /* If processing an 'else if(...)' (i.e. elseflg == SORTOF)
  587.         *   we don't want to indent again later so turn elseflg OFF.
  588.         */
  589.            if (elseflg == SORTOF)
  590.           elseflg = NO;
  591.            }
  592.         }
  593.      break;                     /* loop back around */
  594.  
  595.       /* handle a '#' character (preprocessor directive) */
  596.       case '#':
  597.      string[j++] = c;           /* copy to output buffer */
  598.      while ( (cc=getchr()) != '\n')   /* copy up to newline */
  599.         string[j++] = cc;
  600.      string[j++] = cc;          /* copy the newline to buffer */
  601.      solflg = NO;               /* start-of-line is false */
  602.      putb();                    /* write output buffer */
  603.      solflg = YES;              /* start-of-line is true */
  604.      break;                     /* loop back around */
  605.  
  606.       } /* switch(c) */
  607.  
  608.    } /* while ( (c = getchar()) != EOF) */
  609.  
  610. END:
  611. fclose( inpfile);                   /* close the input file */
  612.  
  613. #ifdef vms
  614.  
  615. if (stdoutflg == NO)
  616.    fclose( outfile);                /* close the output file */
  617.  
  618. #else /* non-vms */
  619.  
  620. /* MS-DOS: rename the original file to .BAK and rename new file */
  621. if (stdoutflg == NO)
  622.    {
  623.    fclose( outfile);                /* close the output file */
  624.    if ( renambak(filename) != SUCCESS)
  625.       {
  626.       fprintf( stderr, "Cannot rename (%s) to .BAK; Output = (%s)\n",
  627.       filename, TEMPNAME);
  628.       exit();
  629.       }
  630.    if (rename(TEMPNAME,filename) != SUCCESS)
  631.       {
  632.       fprintf( stderr, "Cannot rename temporary file; Output = (%s)\n",
  633.       TEMPNAME);
  634.       exit();
  635.       }
  636.    }
  637.  
  638. #endif /* vms */
  639.  
  640. } /*---------------------------- cb() ------------------------------*/
  641.  
  642.  
  643. /* cbinit()  -  initialize the beautifier variables
  644.  *
  645.  */
  646. cbinit()
  647. {
  648. register  i, j;
  649.  
  650. for (i = 0; i < MAXLEVEL; i++)
  651.    {
  652.    aflg[i] = 0;               /* YES/NO flag (has to do with braces) */
  653.    nblk[i] = 0;               /* non-braced blocks at current 'level' */
  654.    sbrclev[i] = 0;            /* saved 'brclev's */
  655.    }
  656.  
  657. for (i = 0; i < MAXBRACE; i++)
  658.    {
  659.    sifflg[i] = 0;             /* saved 'ifflg's */
  660.    siflev[i] = 0;             /* saved 'iflev's */
  661.    sswflg[i] = 0;             /* saved 'swflg's */
  662.    for (j = 0; j < MAXIF; j++)
  663.       {
  664.       saflg[i][j] = 0;        /* saved aflg[] */
  665.       snblk[i][j] = 0;        /* saved nblks[] */
  666.       stabs[i][j] = 0;        /* saved 'tabs' */
  667.       }
  668.    }
  669.    
  670. brclev = 0;                  /* brace {} level: increments on '{'
  671.                   *  and decrements on '}'            */
  672. iflev = 0;                   /* 'if' level */
  673. ifflg = -1;                  /* processing 'if' flag */
  674. tabs = 0;                    /* current level of indentation */
  675. level = 0;                   /* brace level after non-braced block stmt */
  676. addflg = NO;                 /* add-extra-indent flag */
  677. elseflg = NO;                /* processing 'else' flag */
  678. qflg = NO;                   /* question mark flag */
  679. solflg = YES;                /* start-of-line flag */
  680. swflg = NO;                  /* processing 'switch' flag */
  681. paren = 0;                   /* 'parenthesis' level */
  682. peek = -1;                   /* peekahead character */
  683. j = 0;                       /* char index for output buffer */
  684.  
  685. } /*---------------------------- cbinit() ---------------------------*/
  686.  
  687.  
  688. /* ptabs()  -  put out leading white space for proper indentation
  689.  *
  690.  * Returns: nothing
  691.  */
  692. ptabs()
  693. {
  694. register i;
  695.  
  696. /* don't output any leading whitespace unless we are at start-of-line */
  697. if (solflg == NO)
  698.    return;
  699.  
  700. /* if indenting starts at the left column */
  701. if (tabsflg == START0LEVEL)
  702.    i = (tabs-1) * nindent;
  703. /* otherwise indenting starts at the first level */
  704. else
  705.    i = tabs * nindent;
  706.  
  707. /* print leading \t's where possible */
  708. for ( ; i >= 8; i -= 8)
  709.    fprintf( outfile, "\t");
  710.  
  711. /* finish up with spaces */
  712. for ( ; i > 0; i--)
  713.    fprintf( outfile, " ");
  714.  
  715. } /*--------------------------- ptabs() ----------------------------*/
  716.  
  717.  
  718. /* getchr()  -  get character from input file
  719.  *
  720.  * Sets: lastchar to the character gotten from the input file
  721.  *
  722.  * Returns:
  723.  *   peek             if peek contained a lookahead character
  724.  *   getc(inpfile)    otherwise
  725.  */
  726. getchr()
  727. {
  728. /* no lookahead char and lastchar not whitespace */
  729. if (peek < 0  &&  lastchar != ' '  &&  lastchar != '\t')
  730.    pchar = lastchar;
  731.  
  732. /* get the current 'last character' */
  733. lastchar = (peek < 0) ? getc(inpfile) : peek;
  734. peek = -1;
  735.  
  736. return( lastchar == '\r' ? getchr() : lastchar);
  737.  
  738. } /*------------------------- getchr() ----------------------------*/
  739.  
  740.  
  741. /* putb()  -  put the output buffer to the output stream
  742.  *
  743.  */
  744. putb()
  745. {
  746. /* output buffer contains some characters */
  747. if (j > 0)
  748.    {
  749.    /* we are at the start of a line */
  750.    if (solflg == YES)
  751.       {
  752.       if (addflg == YES)         /* we are to add an extra indent */
  753.      {
  754.      if (tabs > 0)           /* if things are currently indented */
  755.         tabs++;              /* then temporarily add more indent */
  756.      ptabs();                /* and output leading white space */
  757.      tabs--;                 /* then restore normal indent level */
  758.      addflg = NO;            /* and turn the flag off */
  759.      }
  760.       else
  761.      ptabs();                /* output leading white space */
  762.       solflg = NO;               /* start-of-line is false now */
  763.       }
  764.    string[j] = '\0';             /* terminate output buffer with null */
  765.    fprintf( outfile, "%s", string);  /* write buffer to output stream */
  766.    j = 0;                        /* mark output buffer as empty now */
  767.    }
  768.  
  769. /* output buffer is empty */
  770. else
  771.    {
  772.    if (solflg == YES)            /* at start-of-line */
  773.       addflg = NO;               /* add-extra-indent is false */
  774.    }
  775.  
  776. } /*--------------------------- putb() -----------------------------*/
  777.  
  778.  
  779. /* lookup()  -  see if string in 'table' is contained in output buffer
  780.  *
  781.  */
  782. lookup( table)
  783. char *table[];
  784. {
  785. char r;
  786. int i,kk,k,l;
  787.  
  788. /* output buffer is empty, can't match that */
  789. if (j < 1)
  790.    return(NO);
  791. /* otherwise nul terminate the output buffer */
  792. else
  793.    string[j] = '\0';
  794.  
  795. /* skip leading spaces in output buffer */
  796. kk = 0;
  797. while (string[kk] == ' ')
  798.    kk++;
  799.  
  800. /* search the entries in the table until a NULL is found */
  801. for (i = 0; table[i] != NULL; i++)
  802.    {
  803.    l = 0;
  804.    for( k=kk; (r = table[i][l++]) == string[k] && r != '\0'; k++)
  805.       ;
  806.    if (r == '\0' && (string[k] < 'a' || string[k] > 'z'))
  807.       return( YES);           /* match found */
  808.    }
  809.  
  810. return( NO);                  /* no match found */
  811.  
  812. } /*-------------------------- lookup() ---------------------------*/
  813.  
  814.  
  815. /* cgets()  -  copy escaped chars and quoted strings to output
  816.  *
  817.  * Returns: last start of sequence character
  818.  */
  819. cgets()
  820. {
  821. char ch;               /* char that starts the current sequence */
  822.  
  823. beg:
  824. /* copy an escaped character to the output */
  825. if ((ch = string[j++] = getchr()) == '\\')
  826.    {
  827.    string[j++] = getchr();
  828.    goto beg;
  829.    }
  830.  
  831. /* character is ' or " */
  832. if (ch == '\'' || ch == '"')
  833.    {
  834.    /* copy until we hit the terminating ' or " */
  835.    while((cc = string[j++] = getchr()) != ch)
  836.       if (cc == '\\')              /* copy escaped characters */
  837.      string[j++] = getchr();   /* unscathed               */
  838.    goto beg;
  839.    }
  840.  
  841. /* if start of char sequence is a newline */
  842. if (ch == '\n')
  843.    {
  844.    putb();                       /* write the output buffer  */
  845.    solflg = YES;                 /* start-of-line is true    */
  846.    addflg = YES;                 /* add-extra-indent is true */
  847.    goto beg;                     /* and start all over again */
  848.    }
  849. else
  850.    return( ch);                  /* otherwise return start of sequence */
  851.  
  852. } /*-------------------------- cgets() -----------------------------*/
  853.  
  854.  
  855. /* gotelse()  -  handle processing after an 'else' is discovered
  856.  *
  857.  * Returns: nothing
  858.  */
  859. gotelse()
  860. {
  861. tabs = stabs[brclev][iflev];         /* return to previous tab level */
  862. nblk[level] = snblk[brclev][iflev];  /* return to previous nblk level*/
  863. aflg[level] = saflg[brclev][iflev];  /* return to previous aflg flag */
  864. ifflg = YES;                         /* show that we are doing an 'if' stmt */
  865.  
  866. } /*------------------------- gotelse() ---------------------------*/
  867.  
  868.  
  869. /* getnl()  -  get remaining white space and comments
  870.  *
  871.  * Return:
  872.  *   1  YES  if we got to a '\n'
  873.  *   0  NO   if we did not get to a '\n'
  874.  */
  875. getnl()
  876. {
  877. /* copy white space to output */
  878. while ((peek = getchr()) == '\t' || peek == ' ')
  879.    {
  880.    string[j++] = peek;
  881.    peek = -1;
  882.    }
  883. /* we may have a comment to gobble up */
  884. if ((peek = getchr()) == '/')
  885.    {
  886.    peek = -1;                    /* don't remember the '/' */
  887.    /* its a comment: copy it to the output */
  888.    if ((peek = getchr()) == '*')
  889.       {
  890.       string[j++] = '/';         /* copy comment start to output */
  891.       string[j++] = '*';
  892.       peek = -1;                 /* don't remember the peek */
  893.       comment();                 /* copy rest of comment to output */
  894.       }
  895.    /* its not a comment: copy the '/' to the output */
  896.    else
  897.       string[j++] = '/';
  898.    }
  899.  
  900. /* return YES is we have gotten to the newline */
  901. if ((peek = getchr()) == '\n')
  902.    {
  903.    peek = -1;                    /* don't remember the peek */
  904.    return( YES);
  905.    }
  906. return( NO);                     /* did not find the newline */
  907.  
  908. } /*--------------------------- getnl() ----------------------------*/
  909.  
  910.  
  911. /* comment()  -  copy remainder of a comment to the output
  912.  *
  913.  * Description:
  914.  *
  915.  * At this point the leading '/*' of the comment have been placed
  916.  * into the output buffer.  This routine copies the remainder of the
  917.  * comment (even across multiple lines) to the output stream
  918.  *
  919.  * Returns: nothing
  920.  */
  921.  
  922. comment()
  923. {
  924. int   temp = tabs;               /* temp tabs storage */
  925. int   multiline = NO;            /* multiline comment flag */
  926.  
  927. string[j] = '\0';                /* nul terminate output buffer */
  928.  
  929. /* process characters inside the comment */
  930. while ( (c = string[j++] = getchr()) != EOF )
  931.    {
  932.    /* reached the end-of-comment */
  933.    if ( j > 1  &&  string[j-2] == '*'  &&  c == '/')
  934.       break;
  935.  
  936.    /* hit a newline: flush buffer to output and handle multiline comment */
  937.    if (c == '\n')
  938.       {
  939.       multiline = YES;           /* set multiline flag */
  940.       putb();                    /* write output buffer */
  941.       string[j] = '\0';          /* nul terminate output string */
  942.       solflg = YES;              /* start-of-line is true */
  943.       tabs = 0;                  /* don't auto-indent next comment lines */
  944.       }
  945.    }
  946.  
  947. /* doing a multiline comment and last line terminated with newline   */
  948. /* make sure we output the buffer before restoring the normal 'tabs' */
  949. if (multiline == YES  &&  getnl() == YES)
  950.    {
  951.    string[j++] = '\n';           /* put newline into output buffer */
  952.    putb();                       /* and flush buffer to output */
  953.    solflg = YES;                 /* start-of-line is true */
  954.    }
  955.  
  956. tabs = temp;                     /* restore tabs */
  957.  
  958. } /*-------------------------- comment() ---------------------------*/
  959.  
  960.  
  961. #ifndef vms
  962. /*--------------------------------------------------------------------
  963.  * renambak()  -  rename filename to .BAK
  964.  *
  965.  * Revision History:
  966.  *   08/08/87 Robert B. Sledge  Initial Creation.
  967.  *
  968.  * Synopsis:
  969.  *   renambak( filename)
  970.  *   char  *filename;           ptr to file to be renamed to .BAK
  971.  *
  972.  * Description:
  973.  *   Check that the 'filename' exists, if not then return FAILURE1.
  974.  *   A copy of the 'filename' string will have its existing file type
  975.  *   stripped and .BAK appended in its place.  Then the file will be
  976.  *   renamed to .BAK.  If this fails due to a previously existing .BAK
  977.  *   file then the existing .BAK file will be deleted and the rename
  978.  *   will be retried.  If this attempt fails then return FAILURE1 for
  979.  *   lack of anything more descriptive.
  980.  *
  981.  * Returns:
  982.  *    0 = SUCCESS
  983.  *   -1 = FAILURE1: Input File Does Not Exist
  984.  *   -2 = FAILURE2: Out of Memory
  985.  *
  986.  * Cautions: Specific to Microsoft C (MS-DOS)
  987.  */
  988.  
  989. int renambak( filename)
  990. char  *filename;                 /* ptr to filename string to rename */
  991. {
  992. int    status = SUCCESS;         /* return status */
  993. char  *malloc();                 /* memory allocation function */
  994. char  *strchr();                 /* character search function */
  995. char  *bakfile;                  /* ptr to .BAK filename */
  996. char  *p;                        /* ptr to '.' in filename */
  997. FILE  *stream;                   /* stream pointer */
  998.  
  999. /* check that the input file exists */
  1000. if ( (stream=fopen(filename,"r")) == NULL)
  1001.    return( FAILURE1);
  1002. fclose( stream);                 /* close the opened stream */
  1003.  
  1004. /* create a temporary copy of the filename */
  1005. if ( (bakfile=malloc(strlen(filename)+6)) == NULL)
  1006.    return( FAILURE2);
  1007. strcpy( bakfile, filename);      /* copy 'filename' to 'bakfile' */
  1008.  
  1009. /* create the .BAK file name string */
  1010. if ( (p=strchr(bakfile,'.')) != NULL)  /* ptr to '.' in the string */
  1011.    *p = '\0';                    /* terminate string at the "." */
  1012. strcat( bakfile, ".BAK");        /* and add .BAK to the end of the string */
  1013.  
  1014. /* rename existing file to .BAK */
  1015. if ( rename(filename,bakfile) != SUCCESS)
  1016.    {                             /* another .BAK file is in the way      */
  1017.    unlink( bakfile);             /* try deleting an existing .BAK file   */
  1018.    if ( rename(filename,bakfile) != SUCCESS)
  1019.       status = FAILURE1;         /* looks like its just not our day      */
  1020.    }
  1021.  
  1022. free( bakfile);                  /* free malloc'ed memory */
  1023. return( status);                 /* and return our status */
  1024.  
  1025. } /*--------------------------- renambak() ----------------------------*/
  1026. #endif /* ifndef vms */
  1027.  
  1028.  
  1029. #ifdef vms
  1030.  
  1031. /* findfile.c  -  return all filespecs that match the wildcard filespec
  1032.  *
  1033.  * Edit History:
  1034.  *   03/02/87 RBS Initial Creation.
  1035.  *
  1036.  * Synopsis:
  1037.  *   char *findfile( filespec)
  1038.  *   char   *filespec        Pointer to string containing wildcard filespec
  1039.  *
  1040.  * Description: The file specification (possibly containing wildcards) is
  1041.  *   passed by pointer "filespec".  A pointer to the first matching file
  1042.  *   specification will be returned.  Successive calls to findfile() with the
  1043.  *   same "filespec" will return successive matching file specs.  When no more
  1044.  *   matching files are found a NULL will be returned.  If the "filespec" is
  1045.  *   changed before all matching files have been returned the routine will 
  1046.  *   start a new file context (effectively erasing the list of remaining files
  1047.  *   for the previous context).
  1048.  *
  1049.  * Returns: Pointer to a matching filespec, NULL if no more files match or
  1050.  *   an error condition occurs.
  1051.  *
  1052.  * Cautions: This routine is specific to VAX/VMS.
  1053.  */
  1054.  
  1055. #include <descrip.h>        /* for string descriptor definitions */
  1056. #include <ssdef.h>        /* defs for system services return values */
  1057. #include <rms.h>        /* def for RMS$_NORMAL */
  1058.  
  1059. #define  MATCH 0        /* strcmp() returns for equal strings */
  1060.  
  1061. char *findfile( filespec)
  1062. char   *filespec;        /* Ptr to string containing wildcard filespec */
  1063. {
  1064. /* local variables */
  1065. struct dsc$descriptor_s ifile;    /* input file string descriptor structure */
  1066. struct dsc$descriptor_s rfile;    /* result file string descriptor structure */
  1067. static char inpfile[256];       /* storage for the input file specification */
  1068. static struct            /* varying string storage structure */
  1069.   {
  1070.   unsigned short curlen;    /* current length of varying string */
  1071.   char body[256];               /* body of varying string */
  1072.   } vs;
  1073. int  status;            /* return status from LIB$FIND_FILE */
  1074. static unsigned context=0;    /* used by LIB$FIND_FILE to save file context */
  1075.  
  1076. /* this is a new input file spec: initialize things */
  1077. if ( strcmp(filespec,inpfile) != MATCH)
  1078.   {
  1079.   strcpy( inpfile, filespec);        /* copy filespec to static string */
  1080.   /* there is a current file context: end it since we are starting fresh */
  1081.   if (context != 0)
  1082.     LIB$FIND_FILE_END( &context);    /* end previous context */
  1083.   }
  1084.  
  1085. /* setup the descriptor for the input (wildcard) filespec string */
  1086. ifile.dsc$w_length  = strlen(inpfile);    /* string length */
  1087. ifile.dsc$a_pointer = inpfile;        /* pointer to string */
  1088. ifile.dsc$b_class   = DSC$K_CLASS_S;    /* fixed-length descriptor class */
  1089. ifile.dsc$b_dtype   = DSC$K_DTYPE_T;    /* ASCII string type */
  1090.  
  1091. /* setup the descriptor for the output (matching) filespec string */
  1092. rfile.dsc$w_length  = 255;              /* maximum filename length */
  1093. rfile.dsc$a_pointer = &vs;        /* ptr to string structure */
  1094. rfile.dsc$b_class   = DSC$K_CLASS_VS;    /* varying string class */
  1095. rfile.dsc$b_dtype   = DSC$K_DTYPE_VT;    /* varying string type */
  1096. vs.curlen = 0;                /* no matching string yet */
  1097.  
  1098. /* parse the component item from the file specification */
  1099. status = LIB$FIND_FILE( &ifile, &rfile, &context, 0, 0, 0, 0);
  1100. vs.body[vs.curlen] = '\0';        /* null terminate the string */
  1101.  
  1102. #ifdef DEBUG
  1103. printf("LIB$FIND = %X, file = %.255s\n", status, vs.body);
  1104. #endif
  1105.  
  1106. if (status == RMS$_NORMAL)
  1107.   return(vs.body);
  1108. else
  1109.   return(NULL);
  1110.  
  1111. } /*-------------------------- findfile() -------------------------*/
  1112.  
  1113. #endif /* ifdef vms */
  1114.